package cn.tedu.medicalappointmentsystemk.service.impl;

import cn.tedu.medicalappointmentsystemk.dao.persist.repository.DepartmentRepository;
import cn.tedu.medicalappointmentsystemk.dao.persist.repository.UserRepository;
import cn.tedu.medicalappointmentsystemk.handler.ServiceException;
import cn.tedu.medicalappointmentsystemk.pojo.bo.*;
import cn.tedu.medicalappointmentsystemk.pojo.param.DepartmentAddParam;
import cn.tedu.medicalappointmentsystemk.pojo.param.DepartmentUpdateParam;
import cn.tedu.medicalappointmentsystemk.pojo.po.DepartmentPO;
import cn.tedu.medicalappointmentsystemk.pojo.po.PageData;
import cn.tedu.medicalappointmentsystemk.pojo.po.UserPO;
import cn.tedu.medicalappointmentsystemk.pojo.vo.DepartmentSelectDoctorVO;
import cn.tedu.medicalappointmentsystemk.response.ServiceCode;
import cn.tedu.medicalappointmentsystemk.service.DepartmentService;
import cn.tedu.medicalappointmentsystemk.util.PageInfoToPageDataConverter;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class DepartmentServiceImpl implements DepartmentService {
    @Autowired
    private DepartmentRepository departmentRepository;

    @Autowired
    private UserRepository userRepository;

    @Value("${medical.dao.default-query-page-size}")
    private int pageSize;

    @Value("${medical.redis.duration-in-seconds}")
    private int Seconds;

    @Autowired
    private StringRedisTemplate redisTemplate;

    private void deleteRedisTemplate(){
        Set<String> keys = redisTemplate.keys(DEPARTMENT_REDIS_HEADER+"*");

        if (keys != null) {
            for (String key : keys) {
                redisTemplate.delete(key);
            }
        }
    }
    @Override
    public void addDepartment(DepartmentAddParam departmentAddParam) {
        String newName=departmentAddParam.getName();
        Integer row = departmentRepository.selectByName(newName);
        if(row > 0){
            String message="该科室已存在";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_INSERT,message);
        }
        DepartmentPO addDepartmentPO=new DepartmentPO();
        BeanUtils.copyProperties(departmentAddParam,addDepartmentPO);
        addDepartmentPO.setNumber("Dpm"+(""+System.currentTimeMillis()).substring(5));
        String userNickname = userRepository.selectNicknameById(departmentAddParam.getUserId());
        addDepartmentPO.setCreateUser(userNickname);
        addDepartmentPO.setUpdateUser(userNickname);
        Long level = departmentAddParam.getLevel();
        if (level==null){
            addDepartmentPO.setType(0L);
        }else {
            Long typeLevel = updateDepartmentType(level);
            while (typeLevel!=null){
                typeLevel = updateDepartmentType(typeLevel);
            }
        }
        Integer rows = departmentRepository.addDepartment(addDepartmentPO);
        if(rows!=1){
            String message="新增科室失败!请稍后再试";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_INSERT,message);
        }
        deleteRedisTemplate();
    }

    public Long updateDepartmentType(Long level){
        DepartmentPO updateDepartmentTypePO = new DepartmentPO();
        updateDepartmentTypePO.setId(level);
        updateDepartmentTypePO.setType(departmentRepository.selectById(level).getType()+1);
        Integer rows = departmentRepository.update(updateDepartmentTypePO);
        if (rows!=1){
            String message="修改科室上级失败!请稍后再试";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_INSERT,message);
        }
        return departmentRepository.selectById(level).getLevel();
    }

    @Override
    public void updateDepartment(DepartmentUpdateParam departmentUpdateParam,Long userId) {
        DepartmentPO departmentPO=new DepartmentPO();
        BeanUtils.copyProperties(departmentUpdateParam,departmentPO);
        UserPO userPO = userRepository.selectById(userId);
        departmentPO.setUpdateUser(userPO.getNickname());
        Integer rows = departmentRepository.update(departmentPO);
        if(rows!=1){
            String message="更新失败";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_UPDATE,message);
        }
        deleteRedisTemplate();
    }

    @Override
    public DepartmentSelectByIdBO selectDepartmentById(Long id) {
        DepartmentPO po = departmentRepository.selectById(id);
        DepartmentSelectByIdBO bo = new DepartmentSelectByIdBO();
        BeanUtils.copyProperties(po,bo);
        return bo;
    }

    @Override
    public List<DepartmentSelectLevelBO> selectDepartmentLevel(Long id) {
        String cacheKey = DEPARTMENT_REDIS_HEADER + "level:" + id;
        ValueOperations<String, String> opsForString = redisTemplate.opsForValue();
        String departmentJson = opsForString.get(cacheKey);
        if (StringUtils.isEmpty(departmentJson)) {
            List<DepartmentPO> listPO = departmentRepository.select(id);
            List<DepartmentSelectLevelBO> listBO = new ArrayList<>();
            for (DepartmentPO po : listPO) {
                DepartmentSelectLevelBO bo = new DepartmentSelectLevelBO();
                BeanUtils.copyProperties(po, bo);
                listBO.add(bo);
            }
            opsForString.set(cacheKey, JSON.toJSONString(listBO),
                    Seconds+new Random().nextInt(Seconds), TimeUnit.SECONDS);
            return listBO;
        }
        return JSON.toJavaObject(JSON.parseObject(departmentJson), List.class);
    }

    @Override
    public List<DepartmentSelectLevelBO> selectDepartmentLevel() {
        String cacheKey = DEPARTMENT_REDIS_HEADER + "level";
        ValueOperations<String, String> opsForString = redisTemplate.opsForValue();
        String departmentJson = opsForString.get(cacheKey);
        if (StringUtils.isEmpty(departmentJson)) {
            List<DepartmentPO> listPO = departmentRepository.select();
            List<DepartmentSelectLevelBO> listBO = new ArrayList<>();
            for (DepartmentPO po : listPO) {
                DepartmentSelectLevelBO bo = new DepartmentSelectLevelBO();
                BeanUtils.copyProperties(po, bo);
                listBO.add(bo);
            }
            departmentJson = JSON.toJSONString(listBO);
            opsForString.set(cacheKey, departmentJson,
                    Seconds+new Random().nextInt(Seconds), TimeUnit.SECONDS);
            return listBO;
        }else {
            return JSON.toJavaObject(JSON.parseArray(departmentJson), List.class);
        }
    }

    @Override
    public PageData<DepartmentSelectBO> selectDepartment(Integer pageNum) {
        String cacheKey = DEPARTMENT_REDIS_HEADER + "pageNum:" + pageNum;
        ValueOperations<String,String> opsForString = redisTemplate.opsForValue();
        String departmentJson = opsForString.get(cacheKey);
        if (StringUtils.isEmpty(departmentJson)) {
            PageHelper.startPage(pageNum, pageSize);
            Page<DepartmentSelectBO> page = departmentRepository.selectDepartment();
            PageInfo<DepartmentSelectBO> pageInfo = new PageInfo<>(page);
            PageData<DepartmentSelectBO> pageData = PageInfoToPageDataConverter.convert(pageInfo);
            opsForString.set(cacheKey,JSON.toJSONString(pageData),
                    Seconds+new Random().nextInt(Seconds),TimeUnit.SECONDS);
            return pageData;
        }else {
            return JSON.toJavaObject(JSON.parseObject(departmentJson),PageData.class);
        }
    }

    @Override
    public void deleteDepartment(Long id) {
        Integer row = departmentRepository.deleteById(id);
        if (row != 1){
            String message="删除失败";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_DELETE,message);
        }
        deleteRedisTemplate();
    }

    @Override
    public List<DoctorSelectTypeBO> selectDoctorByDepartmentId(Long id) {
        String cacheKey = DOCTOR_REDIS_HEADER + "DepartmentId:" + id;
        ValueOperations<String,String> opsForString = redisTemplate.opsForValue();
        String doctorJson = opsForString.get(cacheKey);
        if (StringUtils.isEmpty(doctorJson)) {
            List<DepartmentSelectDoctorVO> voList = departmentRepository.selectDoctorByDepartmentId(id);
            List<DoctorSelectTypeBO> boList = new ArrayList<>();
            for (DepartmentSelectDoctorVO vo : voList) {
                DoctorSelectTypeBO bo = new DoctorSelectTypeBO();
                BeanUtils.copyProperties(vo, bo);
                boList.add(bo);
            }
            opsForString.set(cacheKey,JSON.toJSONString(boList),
                    Seconds + new Random().nextInt(Seconds) , TimeUnit.SECONDS);
            return boList;
        }else{
            return JSON.toJavaObject(JSON.parseArray(doctorJson),List.class);
        }
    }

    @Override
    public PageData<DepartmentSelectBO> searchLastWeek(Integer pageNum) {
        PageHelper.startPage(pageNum,pageSize);
        Page<DepartmentSelectBO> page = departmentRepository.searchLastWeek();
        PageInfo<DepartmentSelectBO> pageInfo = new PageInfo<>(page);
        return PageInfoToPageDataConverter.convert(pageInfo);
    }

    @Override
    public PageData<DepartmentSelectBO> searchLastMonth(Integer pageNum) {
        PageHelper.startPage(pageNum,pageSize);
        Page<DepartmentSelectBO> page = departmentRepository.searchLastMonth();
        PageInfo<DepartmentSelectBO> pageInfo = new PageInfo<>(page);
        return PageInfoToPageDataConverter.convert(pageInfo);
    }

    @Override
    public PageData<DepartmentSelectBO> searchToday(Integer pageNum) {
        PageHelper.startPage(pageNum,pageSize);
        Page<DepartmentSelectBO> page = departmentRepository.searchToday();
        PageInfo<DepartmentSelectBO> pageInfo = new PageInfo<>(page);
        return PageInfoToPageDataConverter.convert(pageInfo);
    }

    @Override
    public List<DepartmentSelectBO> selectByName(String name) {
        return departmentRepository.departmentSelectByName(name);
    }
}
